home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / net / bind-contrib.tar.gz / bind-contrib.tar / contrib / misc / updatedns.shar / makeDNS.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-25  |  12.8 KB  |  535 lines

  1. /* makeDNS.c -- generate DNS RRs from /etc/hosts
  2.  * Copyright (c) 1991, 1992 Department of Computer Science, University of
  3.  * Edinburgh.  Non-commercial use and redistribution is permitted provided this
  4.  * notice remains intact and any modifications are flagged.
  5.  *
  6.  * This software is offered "as is", with no warranty or support whatsoever.
  7.  * Please send comments to gdmr@dcs.ed.ac.uk.
  8.  */
  9.  
  10. /* Generate a set of DNS RR files from /etc/hosts and some configuration
  11.  * files, under a reasonable set of assumptions.  The program expects to
  12.  * be running in the target directory.  It reads the file ".configure" in
  13.  * that directory.  The file consists of a sequence of "wire" records, one
  14.  * per line, each one listing the network number, netmask, RR file, header
  15.  * file and full domain name for all hosts on that wire.  Alternatively,
  16.  * a "domain" record consists of 0.0.0.0 as network number, domain, RR file
  17.  * and header file.
  18.  *
  19.  * The /etc/hosts file is read in, and hosts are added to a 2-way linked list,
  20.  * sorted alphabetically by host name (ordering in the DNS doesn't matter,
  21.  * and this sorting allows the program's assumptions to be implemented).
  22.  * Primary names are held with their corresponding IP address, while aliases
  23.  * have the name of the corresponding primary.
  24.  *
  25.  * Once the hosts file has been read in, the output files are opened and
  26.  * the constant header information is written (with the sequence number
  27.  * properly updated).  The hosts list is then scanned in ascending order
  28.  * and the corresponding entries written according to the following
  29.  * heuristics: if a host name has as its leading component one of the
  30.  * preceding hosts then it is assumed to be a second interface on a
  31.  * multi-homed host, and an additional A record is written; and the domain
  32.  * of a host is taken to be that of its first A record, as defined in the
  33.  * corresponding "wire" entry.  Finally the program exits with a zero status.
  34.  *
  35.  * Should any errors occur, the program will exit with a non-zero status.
  36.  */
  37.  
  38. #define HOSTS "/etc/hosts"
  39. #define CONFIG "Configure"
  40. #define LOG "Log"
  41. #define MAXWIRE 63
  42. #define MAXDOMAIN 5
  43. #define LINEBUFFER 120
  44.  
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47. #include <ctype.h>
  48. #include <pwd.h>
  49. #include <sys/time.h>
  50. #include <fcntl.h>
  51. #include <time.h>
  52.  
  53. typedef struct _domain {
  54.     char *domainname;
  55.     char *RRfile;
  56.     char *headerfile;
  57.     char *otherZonefile;
  58.     char *MXfile;
  59.     FILE *file;
  60.     FILE *other;
  61.     char *MXdata;
  62. } domain;
  63.  
  64. typedef struct _wire {
  65.     long number;
  66.     long netmask;
  67.     char *RRfile;
  68.     char *headerfile;
  69.     char *domainname;
  70.     FILE *file;
  71.     domain *d;
  72. } wire;
  73.  
  74. typedef struct _host {
  75.     struct _host *forward;
  76.     struct _host *backward;
  77.     long IP;
  78.     char *name;
  79.     struct _host *primary;
  80.     wire *w;
  81. } host;
  82.  
  83. static host *hostlist;
  84. static wire wireTable[MAXWIRE];
  85. static domain domainTable[MAXDOMAIN];
  86. static int domains, wires;
  87.  
  88. void readconfig();
  89. void readhosts();
  90. void printhosts();
  91. void openfiles();
  92. void closefiles();
  93.  
  94. main()
  95. {    readconfig();
  96.     readhosts();
  97.     openfiles();
  98.     printhosts();
  99.     closefiles();
  100.     return 0;
  101. }
  102.  
  103. static void addhost(h)
  104. host *h;
  105. {    host *x;
  106.     if (hostlist == NULL) {
  107.         /* List empty, easy case */
  108.         h->forward = NULL;
  109.         h->backward = NULL;
  110.         hostlist = h;
  111.         return;
  112.     }
  113.     x = hostlist;
  114.     /* Skip to insertion point */
  115.     while (strcmp(x->name, h->name) < 0) {
  116.         if (x->forward) {
  117.             /* More, skip */
  118.             x = x->forward;
  119.         }
  120.         else {
  121.             /* Add at the tail of the list */
  122.             h->forward = NULL;
  123.             h->backward = x;
  124.             x->forward = h;
  125.             return;
  126.         }
  127.     }
  128.     /* Sanity check: duplicate? */
  129.     if (!strcmp(x->name, h->name)) {
  130.         (void) fprintf(stderr, "%s duplicate!\n", h->name);
  131.         return;
  132.     }
  133.     /* Insert before x */
  134.     h->forward = x;
  135.     h->backward = x->backward;
  136.     if (x->backward) x->backward->forward = h;    /* Middle */
  137.     else hostlist = h;                /* Head */
  138.     x->backward = h;
  139. }
  140.  
  141. static long IPconvert(ch)
  142. char **ch;
  143. {    long N1, N2, N3, N4;
  144.     N1 = strtol(*ch, ch, 10);  (*ch)++;
  145.     N2 = strtol(*ch, ch, 10);  (*ch)++;
  146.     N3 = strtol(*ch, ch, 10);  (*ch)++;
  147.     N4 = strtol(*ch, ch, 10);  (*ch)++;
  148.     return (N1 << 24) | (N2 << 16) | (N3 << 8) | N4;
  149. }
  150.  
  151. static char *extractname(ch)
  152. char **ch;
  153. {    char *it;
  154.     char *name;
  155.     int n = 0;
  156.     while (isspace(**ch)) (*ch)++;
  157.     if (**ch == '\0' || **ch == '#') return NULL;
  158.     it = *ch;
  159.     while (!isspace(**ch)) {
  160.         (*ch)++;
  161.         n++;
  162.     }
  163.     **ch = '\0';  (*ch)++;
  164.     name = (char *) malloc(n + 1);
  165.     strcpy(name, it);
  166.     return name;
  167. }
  168.  
  169. static wire *findWire(IP)
  170. long IP;
  171. {    int n;
  172.     wire *w;
  173.     if (IP == 0) return NULL;
  174.     for (n = 0, w = wireTable; n < wires; n++, w++) {
  175.         if ((IP & w->netmask) == w->number) {
  176.             return w;
  177.         }
  178.     }
  179.     return NULL;
  180. }
  181.  
  182. static domain *findDomain(name)
  183. char *name;
  184. {    int n;
  185.     domain *d;
  186.     for (n = 0, d = domainTable; n < domains; n++, d++) {
  187.         if (!strcmp(name, d->domainname)) {
  188.             return d;
  189.         }
  190.     }
  191.     return NULL;
  192. }
  193.  
  194. static void readhosts()
  195. {    FILE *hosts;
  196.     host *h, *ph;
  197.     char *ch;
  198.     char buffer[LINEBUFFER];
  199.     long IP;
  200.     char *primary;
  201.     char *alias;
  202.     wire *w;
  203.  
  204.     if ((hosts = fopen(HOSTS, "r")) == NULL) {
  205.         (void) fprintf(stderr, "Failed to open %s\n", HOSTS);
  206.         exit(1);
  207.     }
  208.  
  209.     for (;;) {
  210.         if ((ch = fgets(buffer, LINEBUFFER, hosts)) == NULL) break;
  211.         while (isspace(*ch)) ch++;
  212.         if (*ch == '\0' || *ch == '#') continue;
  213.         IP = IPconvert(&ch);
  214.         if ((w = findWire(IP)) == NULL) continue;
  215.         primary = extractname(&ch);
  216.         ph = (host *) malloc(sizeof(host));
  217.         ph->IP = IP;
  218.         ph->w = w;
  219.         ph->name = primary;
  220.         ph->primary = NULL;
  221.         addhost(ph);
  222.         while (*ch != '\0') {
  223.             alias = extractname(&ch);
  224.             if (alias == NULL) break;
  225.             h = (host *) malloc(sizeof(host));
  226.             h->IP = 0;
  227.             h->w = w;
  228.             h->name = alias;
  229.             h->primary = ph;
  230.             addhost(h);
  231.         }
  232.     }
  233.     (void) fclose(hosts);
  234. }
  235.  
  236. static host *findPrincipal(like)
  237. host *like;
  238. {    host *h;
  239.     int l, n;
  240.  
  241.     h = like->backward;
  242.     l = strlen(like->name);
  243.     while (h) {
  244.         if (*(h->name) != *(like->name)) return NULL;
  245.         n = strlen(h->name);
  246.         if ((n < l) && !isalnum(like->name[n]) &&
  247.                 !strncmp(h->name, like->name, n)) {
  248.             return h;
  249.         }
  250.         h = h->backward;
  251.     }
  252.     return NULL;
  253. }
  254.  
  255. #define  printIP(file, IP) \
  256.     (void) fprintf(file, "%d.%d.%d.%d", \
  257.         (IP >> 24) & 255, (IP >> 16) & 255, (IP >> 8) & 255, IP & 255)
  258.  
  259. /* printhosts has four cases:
  260.  *   1    IP address, no principal entry -- write the name as it stands, plus
  261.  *    the reverse name, again as it stands.
  262.  *   2    IP address plus principal entry -- write out the address as for the
  263.  *    principal entry, plus the current name as another A RR.  Write the
  264.  *    reverse entry as pointing to the principal name.
  265.  *   3    alias, no principal entry -- write a CNAME RR pointing to the primary.
  266.  *   4    alias plus principal entry -- write an A RR with the primary's address.
  267.  *
  268.  * For example, suppose the /etc/hosts file has the following:
  269.  *    129.215.64.48  baleshare baleshare-b agfahost
  270.  *    29.215.160.155 baleshare-gw baleshare-a
  271.  * Then baleshare is case 1, baleshare-gw is case 2, baleshare-a and
  272.  * baleshare-b are case 4, and agfahost is case 3.  Confused?  BTW, changing
  273.  * baleshare-gw to fred, say, would break the algorithm -- the main name of the
  274.  * second interface better be related to the main name of the first!
  275.  */
  276.  
  277. void printhosts()
  278. {    host *h, *m, *x;
  279.     wire *w;
  280.     FILE *f;
  281.     int dotted;
  282.  
  283.     h = hostlist;
  284.     while (h) {
  285.         m = findPrincipal(h);
  286.         if (h->IP) {
  287.             if (m) {
  288.                 /* Case 2 */
  289.                 /* A RR for name */
  290.                 (void) fprintf(m->w->d->file,
  291.                     "%-23s IN\tA\t", h->name);
  292.                 printIP(m->w->d->file, h->IP);
  293.                 (void) putc('\n', m->w->d->file);
  294.                 if (m->w->d->MXdata) {
  295.                     (void) fputs(m->w->d->MXdata,
  296.                         m->w->d->file);
  297.                 }
  298.                 /* A RR for principal's name */
  299.                 (void) fprintf(m->w->d->file,
  300.                     "%-23s IN\tA\t", m->name);
  301.                 printIP(m->w->d->file, h->IP);
  302.                 (void) putc('\n', m->w->d->file);
  303.                 /* back-pointer -> principal */
  304.                 (void) fprintf(h->w->file,
  305.                     "%d\tIN\tPTR\t%s.%s.\n",
  306.                     h->IP & (~h->w->netmask),
  307.                     m->name, m->w->d->domainname);
  308.                 if (m->w->d->other) {
  309.                     (void) fprintf(m->w->d->other,
  310.                         "%-23s IN\tCNAME\t%s.%s.\n",
  311.                         h->name, m->name,
  312.                         m->w->d->domainname);
  313.                 }
  314.             }
  315.             else {
  316.                 /* Case 1 */
  317.                 dotted = (int) index(h->name, '.');
  318.                 if (!dotted) {
  319.                     (void) fprintf(h->w->d->file,
  320.                         "%-23s IN\tA\t", h->name);
  321.                     printIP(h->w->d->file, h->IP);
  322.                     (void) putc('\n', h->w->d->file);
  323.                     if (h->w->d->MXdata) {
  324.                         (void) fputs(h->w->d->MXdata,
  325.                             h->w->d->file);
  326.                     }
  327.                     if (h->w->d->other) {
  328.                         (void) fprintf(h->w->d->other,
  329.                             "%-23s IN\tCNAME\t%s.%s.\n",
  330.                             h->name, h->name,
  331.                             h->w->d->domainname);
  332.                     }
  333.                 }
  334.                 (void) fprintf(h->w->file,
  335.                     dotted ? "%d\tIN\tPTR\t%s\n"
  336.                         : "%d\tIN\tPTR\t%s.%s.\n",
  337.                     h->IP & (~h->w->netmask),
  338.                     h->name, h->w->d->domainname);
  339.             }
  340.         }
  341.         else {
  342.             if (m) {
  343.                 /* Case 4 */
  344.                 (void) fprintf(m->w->d->file,
  345.                     "%-23s IN\tA\t", h->name);
  346.                 printIP(m->w->d->file, h->primary->IP);
  347.                 (void) putc('\n', m->w->d->file);
  348.                 if (m->w->d->MXdata) {
  349.                     (void) fputs(m->w->d->MXdata,
  350.                         m->w->d->file);
  351.                 }
  352.                 if (m->w->d->other) {
  353.                     (void) fprintf(m->w->d->other,
  354.                         "%-23s IN\tCNAME\t%s.%s.\n",
  355.                         h->name, m->name,
  356.                         m->w->d->domainname);
  357.                 }
  358.             }
  359.             else {
  360.                 /* Case 3 */
  361.                 x = findPrincipal(h->primary);
  362.                 if (!x) x = h->primary;
  363.                 (void) fprintf(x->w->d->file,
  364.                     "%-23s IN\tCNAME\t%s.%s.\n",
  365.                     h->name, x->name,
  366.                     x->w->d->domainname);
  367.                 if (x->w->d->other) {
  368.                     (void) fprintf(x->w->d->other,
  369.                         "%-23s IN\tCNAME\t%s.%s.\n",
  370.                         h->name, x->name,
  371.                         x->w->d->domainname);
  372.                 }
  373.             }
  374.         }
  375.         h = h->forward;
  376.     }
  377. }
  378.  
  379. static void readconfig()
  380. {    FILE *config;
  381.     long IP;
  382.     char *ch;
  383.     char buffer[LINEBUFFER];
  384.     wire *w;
  385.     domain *d;
  386.  
  387.     if ((config = fopen(CONFIG, "r")) == NULL) {
  388.         (void) fprintf(stderr, "Failed to open %s\n", CONFIG);
  389.         exit(1);
  390.     }
  391.     for (;;) {
  392.         if ((ch = fgets(buffer, LINEBUFFER, config)) == NULL) break;
  393.         while (isspace(*ch)) ch++;
  394.         if (*ch == '\0' || *ch == '#') continue;
  395.         IP = IPconvert(&ch);
  396.         if (IP) {
  397.             /* Wire record */
  398.             w = wireTable + wires++;
  399.             w->number = IP;
  400.             w->netmask = IPconvert(&ch);
  401.             w->RRfile = extractname(&ch);
  402.             w->headerfile = extractname(&ch);
  403.             w->domainname = extractname(&ch);
  404.             w->file = stderr;  /* meantime */
  405.             w->d = findDomain(w->domainname);
  406.             if (!w->d) {
  407.                 (void) fprintf(stderr, "Undefined domain %s:\n",
  408.                     w->domainname);
  409.                 (void) fputs(buffer, stderr);
  410.                 (void) fputc('\n', stderr);
  411.                 exit(2);
  412.             }
  413.         }
  414.         else {
  415.             /* Domain record */
  416.             d = domainTable + domains++;
  417.             d->domainname = extractname(&ch);
  418.             d->RRfile = extractname(&ch);
  419.             d->headerfile = extractname(&ch);
  420.             d->otherZonefile = extractname(&ch);
  421.             d->MXfile = extractname(&ch);
  422.             d->file = stderr;  /* meantime */
  423.             d->other = NULL;
  424.             d->MXdata = NULL;
  425.         }
  426.     }
  427.     (void) fclose(config);
  428. }
  429.  
  430. static void writeheader(f, h, MXdata)
  431. FILE *f;
  432. char *h;
  433. char *MXdata;
  434. {    static struct passwd *pwd;
  435.     time_t tt;
  436.     static struct tm *ttm;
  437.     static char *t;
  438.     static char stamp[20];
  439.     FILE *hf, *l;
  440.     char buffer[LINEBUFFER];
  441.  
  442.     if (!pwd) {
  443.         pwd = getpwuid(getuid());
  444.         endpwent();
  445.         tt = time(NULL);
  446.         ttm = localtime(&tt);
  447.         (void) sprintf(stamp, "%d%3.3d%3.3d",
  448.             ttm->tm_year, ttm->tm_yday,
  449.             ((60 * ttm->tm_hour) + ttm->tm_min) >> 1);
  450.         t = asctime(ttm);
  451.         if (l = fopen(LOG, "a")) {
  452.             fprintf(l, "Generated by %s on %s", pwd->pw_name, t);
  453.             fclose(l);
  454.         }
  455.     }
  456.     (void) fprintf(f, ";; Generated by %s on %s\n", pwd->pw_name, t);
  457.     if ((hf = fopen(h, "r")) == NULL) {
  458.         (void) fprintf(stderr, "Can't open header file %s\n", h);
  459.         exit(4);
  460.     }
  461.     (void) fprintf(f, ";; Including %s\n", h);
  462.     for (;;) {
  463.         if (fgets(buffer, LINEBUFFER, hf) == NULL) break;
  464.         (void) fprintf(f, buffer, stamp);
  465.     }
  466.     (void) fclose(hf);
  467.     (void) fprintf(f, ";; End of %s\n\n", h);
  468.     if (MXdata) {
  469.         (void) fputc('@', f);
  470.         (void) fputs(MXdata, f);
  471.         (void) fputc('\n', f);
  472.     }
  473. }
  474.  
  475. static void openfiles()
  476. {    int i;
  477.     int MXfd;
  478.     int MXsize;
  479.     wire *w;
  480.     domain *d;
  481.  
  482.     for (i = 0, d = domainTable; i < domains; i++, d++) {
  483.         if ((d->file = fopen(d->RRfile, "w")) == NULL) {
  484.             (void) fprintf(stderr, "Can't open %s\n", d->RRfile);
  485.             exit(3);
  486.         }
  487.         if (d->otherZonefile) {
  488.             if ((d->other = fopen(d->otherZonefile, "w")) == NULL) {
  489.                 (void) fprintf(stderr, "Can't open %s\n",
  490.                         d->otherZonefile);
  491.                 exit(3);
  492.             }
  493.         }
  494.         if (d->MXfile) {
  495.             if ((MXfd = open(d->MXfile, O_RDONLY, 0)) < 0) {
  496.                 (void) fprintf(stderr, "Can't open %s\n",
  497.                         d->MXfile);
  498.                 exit(3);
  499.             }
  500.             d->MXdata = (char *) malloc(2048);
  501.             if ((MXsize = read(MXfd, d->MXdata, 2048)) < 0) {
  502.                 (void) fprintf(stderr,
  503.                         "Couldn't read from %s\n",
  504.                         d->MXfile);
  505.                 exit(3);
  506.             }
  507.             (void) close(MXfd);
  508.             *(d->MXdata + MXsize) = '\0';
  509.         }
  510.         writeheader(d->file, d->headerfile, d->MXdata);
  511.         if (d->otherZonefile)
  512.             writeheader(d->other, d->headerfile, d->MXdata);
  513.     }
  514.     for (i = 0, w = wireTable; i < wires; i++, w++) {
  515.         if ((w->file = fopen(w->RRfile, "w")) == NULL) {
  516.             exit(3);
  517.         }
  518.         writeheader(w->file, w->headerfile, (char *) 0);
  519.     }
  520. }
  521.  
  522. static void closefiles()
  523. {    int i;
  524.     domain *d;
  525.     wire *w;
  526.  
  527.     for (i = 0, d = domainTable; i < domains; i++, d++) {
  528.         (void) fclose(d->file);
  529.         if (d->other) (void) fclose(d->other);
  530.     }
  531.     for (i = 0, w = wireTable; i < wires; i++, w++) {
  532.         (void) fclose(w->file);
  533.     }
  534. }
  535.